/*
 * Copyright (c) 2020, yifengling0. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. No personal names or organizations' names associated with the
 *    Atomthreads project may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __GNSS_H__
#define __GNSS_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "atom.h"
#include "atommutex.h"
#include "device.h"

#define GNSS_STACK_SIZE    (4096)

enum gnss_signal_t {
	GNSS_SIGNAL_INVALID = 0,
	GNSS_SIGNAL_FIX = 1,
	GNSS_SIGNAL_DIFFERENTIAL = 2,
	GNSS_SIGNAL_PPS = 3,
	GNSS_SIGNAL_RTK = 4,
	GNSS_SIGNAL_FLOAT_RTK = 5,
	GNSS_SIGNAL_ESTIMATED = 6,
	GNSS_SIGNAL_MANUAL = 7,
	GNSS_SIGNAL_SIMULATION = 8,
};

enum gnss_fix_t {
	GNSS_FIX_NONE = 1,
	GNSS_FIX_2D = 2,
	GNSS_FIX_3D = 3,
};

struct gnss_nmea_t {
	enum gnss_signal_t signal;			/* signal quality */
	enum gnss_fix_t fix;				/* fix mode */
	unsigned int used;					/* the count of satellites in used */

	double latitude;					/* latitude in degrees */
	double longitude;					/* longitude in degrees */
	double altitude;					/* altitude in meters above the WGS-84 reference ellipsoid */
	double speed; 						/* speed over the ground in kilometers per hour */
	double track;						/* track angle in degrees true north */
	double mtrack;						/* magnetic track angle in degrees true north */
	double magvar;						/* magnetic variation */

	struct {
		unsigned int year;				/* year */
		unsigned int month;				/* month */
		unsigned int day;				/* day */
		unsigned int hour;				/* hour */
		unsigned int minute;			/* minute */
		unsigned int second;			/* second */
		unsigned int millisecond;		/* millisecond */
	} utc;

	struct {
		double pdop;					/* position dilution of precision */
		double hdop;					/* horizontal dilution of precision */
		double vdop;					/* vertical dilution of precision */
	} precision;

	struct {
		struct {
			unsigned int n;				/* the number of satellites */
			struct {
				unsigned int prn;		/* satellite prn number */
				unsigned int elevation;	/* elevation value in degrees */
				unsigned int azimuth;	/* azimuth value in degrees */
				unsigned int snr;		/* signal noise ratio in db */
			} sv[16];
		} gps;

		struct {
			unsigned int n;				/* the number of satellites */
			struct {
				unsigned int prn;		/* satellite prn number */
				unsigned int elevation;	/* elevation value in degrees */
				unsigned int azimuth;	/* azimuth value in degrees */
				unsigned int snr;		/* signal noise ratio in db */
			} sv[16];
		} beidou;
	} satellite;

	/*
		* Private data
		*/
	char buffer[256];
	int bindex;
	int dindex;
	char* tstart[32];
	char* tend[32];
	int tsize;
};

typedef struct DeviceGnss DeviceGnss;

typedef struct gnssOps
{
	void (*data_ready_event)(const DeviceGnss *dev, const struct gnss_nmea_t *data);
}GnssOps;

typedef struct DeviceGnss {
	Device_t super;
	struct {
		int resetPin;
		struct gnss_nmea_t nmea;
		const char* name;
		const GnssOps* ops;
		ATOM_TCB *tcb;
		void *stack;
		
		void (*init)(DeviceGnss* dev);
		void (*enable)(DeviceGnss* dev);
		void (*disable)(DeviceGnss* dev); 
		int (*dev_read)(DeviceGnss* dev, void* buf, int count);
		int (*dev_write)(DeviceGnss* dev, void* buf, int count);
	}Protected;
	struct{         
    	struct gnss_nmea_t data;
        ATOM_MUTEX lock;
    }Data;
}DeviceGnss;


void DeviceGnssCreate(DeviceGnss* gnss, const DeviceDesc *desc, const GnssOps* ops);
void DeviceGnssGetData(DeviceGnss* gnss, struct gnss_nmea_t *data);

#ifdef __cplusplus
}
#endif

#endif /* __GNSS_H__ */
